Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Silex - Symfony goes micro
Search
Igor Wiedler
October 21, 2011
Programming
11k
14
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Silex - Symfony goes micro
Talk on the Silex microframework as given at symfonyday 2011.
Igor Wiedler
October 21, 2011
More Decks by Igor Wiedler
See All by Igor Wiedler
Redis Bedtime Stories
igorw
1
350
Wide Event Analytics (LISA19)
igorw
4
940
a day in the life of a request
igorw
0
170
production: an owner's manual
igorw
0
190
The Power of 2
igorw
0
330
LISP 1.5 Programmer's Manual: A Dramatic Reading
igorw
0
470
The Moral Character of Software
igorw
1
310
interdisciplinary computing (domcode)
igorw
0
320
miniKanren (clojure berlin)
igorw
1
330
Other Decks in Programming
See All in Programming
Lessons from Spec-Driven Development
simas
PRO
0
150
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
190
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
200
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
Spec-Driven Development with AI-Agents: From High-Level Requirements to Working Software
antonarhipov
2
480
LLM Plugin for Node-REDの利用方法と開発について
404background
0
170
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
190
The NotImplementedError Problem in Ruby
koic
1
680
Vite+ Unified Toolchain for the Web
naokihaba
0
230
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
660
Oxlintのカスタムルールの現況
syumai
6
1.1k
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
170
Featured
See All Featured
Code Review Best Practice
trishagee
74
20k
Being A Developer After 40
akosma
91
590k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
830
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
5.9k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
530
Optimizing for Happiness
mojombo
378
71k
Side Projects
sachag
455
43k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Paper Plane
katiecoart
PRO
1
51k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.9k
30 Presentation Tips
portentint
PRO
1
320
The #1 spot is gone: here's how to win anyway
tamaranovitovic
2
1.1k
Transcript
None
• phpBB • Symfony2 • Silex igorw
None
Silex Symfony goes micro μ
Silex is not Symfony
Microframework
None
What? • Bare bones • Routes mapped to controllers •
The ‘C’ of ‘MVC’ • REST • Single file app
Why?
Sometimes a full-stack framework is too much for a simple
task.
simple
What makes silex special?
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
Http Kernel Interface
Response handle(Request $request)
client
request client
reponse client request
clean
PSR-0
None
Silex is not Symfony
Silex is a user interface for Symfony
require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; });
Phar require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
Application require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; }); Controller
$app->run();
None
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /some/path RewriteCond %{REQUEST_FILENAME} !-f RewriteCond
%{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </IfModule>
server { location / { if (-f $request_filename) { break;
} rewrite ^(.*) /index.php last; } location ~ index\.php$ { fastcgi_pass /var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } }
Wait a minute!
Lambdas λ
$(function () { $("a").click(function (event) { alert("Thanks for visiting!"); });
});
PHP 5.3
$f = function ($a, $b) { return $a + $b;
}; $f(1, 2);
lazy $f = function () { exit; };
nested $f = function () { return function () {
return true; }; }; $g = $f(); $value = $g();
scope $outer = 'world'; $f = function () use ($outer)
{ $inner = 'hello'; return "$inner $outer"; }; => "hello world"
scope $helloWorld = function () { $outer = 'world'; $f
= function () use ($outer) { $inner = 'hello'; return "$inner $outer"; }; return $f(); }
passing $output = function ($info) { echo $info."\n"; }; $doStuff
= function ($output) { $output('doing some magic'); doMagic(); $output('did some magic'); };
factory $userFactory = function ($name) { return new User($name); };
// ... $user = $userFactory($_POST['name']);
Usage
$app->get('/', function () { return "Hello world!"; });
Dynamic Routing
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
Controllers
assert $app->get('/blog/{id}', function ($id) { ... }) ->assert('id', '\d+');
value $app->get('/{page}', function ($page) { ... }) ->value('page', 'index');
bind $app->get('/', function () { ... }) ->bind('homepage'); $app['url_generator']->generate('homepage')
bind $app->get('/blog/{id}', function ($id) { ... }) ->bind('blog_post'); $app['url_generator'] ->generate('blog_post',
array('id' => $id))
convert $app->get('/blog/{post}', function (Post $post) { ... }) ->convert('post', function
($post) use ($app) { $id = (int) $post; return $app['posts']->find($id); });
Before & After
$app->before(function () { ... }); $app->get('/', function () { ...
}); $app->after(function () { ... });
$app->before(function (Request $request) { $loggedIn = $request ->getSession() ->get('logged_in'); if
(!$loggedIn) { return new RedirectResponse('/login'); } });
$app->after(function (Request $request, Response $response) { // tweak the Response
});
$app->after(function ( Request $request, Response $response, ) use ($app) {
$response->headers->set('x-csrf-token', $app['csrf_token']); });
REST
• get • post • put • delete • head
• options • patch
$app->get('/posts/{id}', ...); $app->post('/posts', ...); $app->put('/posts/{id}', ...); $app->delete('/post/{id}', ...);
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $app->post('/message', function (Request $request) { mail(
'
[email protected]
', 'New message', $request->get('body') ); return new Response('Email has been sent!', 201); });
Caching
Error Handling
use Symfony\Component\HttpFoundation\Response; $app->error(function (\Exception $e, $code) { return new Response('Whoops!',
$code); });
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; throw new NotFoundHttpException("Could not find what you were
looking for.");
$app->abort(404, "Could not find the thing.");
$app['debug'] = true;
Redirecting
$app->get('/', function () use ($app) { return $app->redirect('/hello'); });
Pimple
50 NCLOC
Symfony2 DIC Pimple
Symfony2 DIC Pimple Container
Symfony2 DIC Pimple Container Builder
Symfony2 DIC Pimple Container Builder Extension
Symfony2 DIC Pimple Container Builder Extension Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container
ServiceProvider ( )
$container = new Pimple();
$app = new Silex\Application();
Parameters $app['some_parameter'] = 'value'; $app['asset.host'] = 'http://cdn.mysite.com/'; $app['database.dsn'] = 'mysql:dbname=myapp';
Services $app['some_service'] = function () { return new Service(); };
$service = $app['some_service'];
Dependencies $app['some_service'] = function ($app) { return new Service( $app['some_other_service'],
$app['some_service.config'] ); };
Shared $app['some_service'] = $app->share(function () { return new Service(); });
Protected $app['lambda_parameter'] = $app->protect( function ($a, $b) { return $a
+ $b; }); // will not execute the lambda $add = $app['lambda_parameter']; // calling it now echo $add(2, 3);
Exposed Services • debug • request • autoloader • routes
• controllers • dispatcher • resolver • kernel
Service Providers
interface ServiceProviderInterface { function register(Application $app); }
Core Service Providers • doctrine • form • http cache
• monolog • session • swiftmailer • symfony bridges • translation • twig • url generator • validator
Twig
$app->register( new Silex\ServiceProvider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', 'twig.class_path' => __DIR__.'/vendor/twig/lib',
) );
$app->get('/', function () use ($app) { return $app['twig']->render('hello.twig'); });
3rd Party • doctrine orm • pomm (postgres) • predis
• mongo • KyotoTycoon • memcache • rest • markdown • gravatar • buzz • config • solr • profiler • ...
Functional Testing
• src • app.php • web • index.php • tests
• bootstrap.php • YourTest.php
src/app.php require_once __DIR__.'/../vendor/silex.phar'; ... return $app;
web/index.php $app = require_once __DIR__.'/../src/app.php'; $app->run();
tests/bootstrap.php require_once __DIR__.'/../vendor/silex.phar';
use Silex\WebTestCase; class YourTest extends WebTestCase { public function createApp()
{ return require __DIR__.'/../src/app.php'; } // tests... } tests/YourTest.php
public function testAbout() { $client = $this->createClient(); $client->request('GET', '/about'); $response
= $client->getResponse(); $this->assertTrue($response->isOk()); $this->assertContains('trashbin', $response->getContent()); $this->assertContains('github', $response->getContent()); $this->assertContains('igorw', $response->getContent()); }
phpunit.xml.dist <?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true"
convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" syntaxCheck="false" bootstrap="tests/bootstrap.php" > <testsuites> <testsuite name="YourApp Test Suite"> <directory>./tests/</directory> </testsuite> </testsuites> </phpunit>
$ phpunit
None
None
• smallish sites • well-defined scope • prototyping • restful
apis When to use
and many more...
The future
The future • Cookbooks
The future • Cookbooks • Best practices
The future • Cookbooks • Best practices • Symfony2 integration
The future • Cookbooks • Best practices • Symfony2 integration
• FOSUserBundle
The future • Cookbooks • Best practices • Symfony2 integration
• FOSUserBundle • Composer
on github fabpot/Silex fabpot/Pimple
silex.sensiolabs.org
Ω
Questions? joind.in/3699 @igorwesome speakerdeck.com /u/igorw